﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Linq;
using AcctrueWMS.Foundation.Web;
using System.Configuration;

namespace AcctrueWMS.Foundation.Data
{
    public class ModelCacheManager
    {
        private Sorte<string, DataModel> modelCacheList = null;
        private static ModelCacheManager modelCacheManager = null;
        private static object objhelper = new object();

        private ModelCacheManager()
        {
            modelCacheList = new Sorte<string, DataModel>();
        }

        public static ModelCacheManager GetInstace()
        {
            if (modelCacheManager == null)
            {
                lock (objhelper)
                {
                    modelCacheManager = new ModelCacheManager();
                    return modelCacheManager;
                }
            }
            return modelCacheManager;
        }

        public DataModel GetModelByName(string modelName)
        {
            string isCache = ConfigurationManager.AppSettings["isCache"].ToString();
            if (modelCacheList.ContainsKey(modelName) && isCache=="1")
            {
                return modelCacheList[modelName];
            }
            else
            {
                DataModel model = GetDataModelByXml(modelName);
                modelCacheList.Add(modelName, model);
                return model;
            }
        }

        public DataModel GetModelByName(string modelName,IDataModelContext context)
        {
            string isCache = ConfigurationManager.AppSettings["isCache"].ToString();
            DataModel model = null;
            if (modelCacheList.ContainsKey(modelName) && isCache == "1")
            {
                 model= modelCacheList[modelName];
            }
            else
            {
                model = GetDataModelByXml(modelName);
                modelCacheList.Add(modelName, model);                
            }

            model.Context = context;
            return model;
        }

        /// <summary>
        /// 从xml中初始化DataModel 因为没有改变外部静态变量，此静态函数多线程安全。
        /// </summary>
        /// <param name="modelName"></param>
        /// <param name="FilePath"></param>
        /// <returns></returns>
        private static DataModel GetDataModelByXml(string modelName)
        {
            DataModel model = new DataModel(modelName);
            model.Context = Runtime.Context;
            Dictionary<string, Type> dirType = Web.TypeConverter.Converter.DirType;
            //加载DataModel属性
            string fullpathName = string.Empty;
            if (!modelName.Trim().Contains(".xml"))
                fullpathName = Runtime.Context.FilePath + "\\" + modelName.Trim() + ".xml";
            else
                fullpathName = Runtime.Context.FilePath + "\\" + modelName.Trim();
            if (!File.Exists(fullpathName))
            {
                return null; ;
            }
            XDocument xd = XDocument.Load(fullpathName);
            #region 加载Model基本信息
            model.Name = xd.Root.Attribute("name") == null ? string.Empty : xd.Root.Attribute("name").Value;
            model.GeneratingCommand = xd.Root.Attribute("generatingCommand") == null ? string.Empty : xd.Root.Attribute("generatingCommand").Value;
            model.DisplayName = xd.Root.Attribute("displayName") == null ? string.Empty : xd.Root.Attribute("displayName").Value;
            string physicalType = xd.Root.Attribute("physicalType") == null ? string.Empty : xd.Root.Attribute("physicalType").Value;
            model.PhysicalType = (DataModelPhysicalTypeEnum)Enum.Parse(typeof(DataModelPhysicalTypeEnum), physicalType);
            model.KeyColumnName = xd.Root.Attribute("keyColumnName") == null ? string.Empty : xd.Root.Attribute("keyColumnName").Value;
            //wbs 字段配置
            model.WbsCodeColumn = xd.Root.Attribute("wbsCodeColumnName") == null ? string.Empty : xd.Root.Attribute("wbsCodeColumnName").Value;
            //wbs格式配置
            model.WbsCodeGenType = xd.Root.Attribute("wbsCodeGenType") == null ? string.Empty : xd.Root.Attribute("wbsCodeGenType").Value;
            #endregion
            //Model.Columns
            #region 加载DataModel对应的列信息
            IEnumerable<XElement> columns = xd.Root.Element("Columns").Elements();
            foreach (XElement column in columns)
            {
                DataModelColumn modelColumn = new DataModelColumn();
                modelColumn.Model = model;
                modelColumn.Name = column.Attribute("name") == null ? string.Empty : column.Attribute("name").Value;
                modelColumn.DisplayName = column.Attribute("displayName") == null ? string.Empty : column.Attribute("displayName").Value;
                modelColumn.Length = column.Attribute("length") == null ? string.Empty : column.Attribute("length").Value;
                modelColumn.Width = column.Attribute("width") == null ? string.Empty : column.Attribute("width").Value;
                modelColumn.Height = column.Attribute("height") == null ? string.Empty : column.Attribute("height").Value;
                modelColumn.ColumnType = dirType[column.Attribute("columnType").Value];
                modelColumn.Nullable = column.Attribute("nullable") == null ? true : Convert.ToBoolean(column.Attribute("nullable").Value);
                modelColumn.DisplayType = column.Attribute("displayType") == null ? string.Empty : column.Attribute("displayType").Value;
                modelColumn.PhysicalType = column.Attribute("physicalType") == null ? string.Empty : column.Attribute("physicalType").Value.ToLower();
                modelColumn.Visible = column.Attribute("visible") == null ? true : Convert.ToBoolean(column.Attribute("visible").Value);
                modelColumn.Enable = column.Attribute("enable") == null ? true : Convert.ToBoolean(column.Attribute("enable").Value);
                modelColumn.Sortable = column.Attribute("sortable") == null ? false : Convert.ToBoolean(column.Attribute("sortable").Value);
                modelColumn.Sort = column.Attribute("sort") == null ? string.Empty : column.Attribute("sort").Value;
                modelColumn.Searchable = column.Attribute("searchable") == null ? false : Convert.ToBoolean(column.Attribute("searchable").Value);
                modelColumn.Data = column.Attribute("data") == null ? string.Empty : column.Attribute("data").Value;
                modelColumn.Default = column.Attribute("defaultValue") == null ? string.Empty : column.Attribute("defaultValue").Value;
                modelColumn.ValidPattern = column.Attribute("validPattern") == null ? string.Empty : column.Attribute("validPattern").Value;
                modelColumn.Url = column.Attribute("Url") == null ? string.Empty : column.Attribute("Url").Value;
                modelColumn.Style = column.Attribute("style") == null ? string.Empty : column.Attribute("style").Value;
                modelColumn.QueryType = column.Attribute("queryType") == null ? string.Empty : column.Attribute("queryType").Value;
                modelColumn.Format = column.Attribute("format") == null ? string.Empty : column.Attribute("format").Value;
                modelColumn.OrderBy = column.Attribute("orderBy") == null ? string.Empty : column.Attribute("orderBy").Value;

                modelColumn.DataVolideExpr = column.Attribute("DataVolideExpr") == null ? string.Empty : column.Attribute("DataVolideExpr").Value;//数据验证表达式

                //DisplayMember和ValueMember不在此处定义，需要数据源的，默认都是用key,value,text
                //modelColumn.DisplayMember = column.Attribute("displayMember") == null ? string.Empty : column.Attribute("displayMember").Value;
                //modelColumn.ValueMember = column.Attribute("valueMember") == null ? string.Empty : column.Attribute("valueMember").Value;
                ///流水号/生成方式,如果标记该属性,则可自动生成流水号
                modelColumn.SequenceNoGenType = column.Attribute("sequenceNoGenType") == null ? string.Empty : column.Attribute("sequenceNoGenType").Value;
                string musted = column.Attribute("musted") == null ? string.Empty : column.Attribute("musted").Value;
                if (musted.Length > 0)
                    modelColumn.Musted = Convert.ToBoolean(musted);
                else modelColumn.Musted = false;
                model.Columns.Add(modelColumn);
            }

            //新增ROWNUM列   create by tianp
            DataModelColumn modelRowNumColumn = new DataModelColumn();
            modelRowNumColumn.Model = model;
            modelRowNumColumn.Name = "ROWNUM";
            modelRowNumColumn.DisplayName = "序号";
            modelRowNumColumn.Sortable = false;
            modelRowNumColumn.SequenceNoGenType = string.Empty;
            modelRowNumColumn.PhysicalType = "virtual";
            modelRowNumColumn.ColumnType = string.Empty.GetType();

            model.Columns.Add(modelRowNumColumn);
            //end

            #endregion

            //加载Model.Childs和Model.Brothers
            #region 加载DataModel关联,关联包括Brothers和Childs
            IEnumerable<XElement> relationsNode = xd.Root.Element("Relations") == null ? null : xd.Root.Element("Relations").Elements();
            model.Childs = new DataModelCollection(model);

            if (relationsNode != null)
            {
                foreach (XElement relationNode in relationsNode)
                {
                    DataModelRelation relation = new DataModelRelation();
                    string name = relationNode.Attribute("Model").Value;
                    string relationType = relationNode.Attribute("relationType") == null ? "child" : relationNode.Attribute("relationType").Value;

                    //string childModelPath = fullpathName.Replace(fullpathName.Substring(fullpathName.LastIndexOf(@"\")), @"\" + name + ".xml");
                    // this.FilePath = childModelPath;

                    model.Relations.Add(relation);
                    relation.From = model;
                    //relation.To = new DataModel(Runtime.Context, name);
                    ModelCacheManager modelCacheManager = ModelCacheManager.GetInstace();
                    relation.To = modelCacheManager.GetModelByName(name, Runtime.Context);

                    relation.RelationExpression = relationNode.Attribute("expression").Value;
                    relation.RelationType = relationType == "child" ? RelationType.Child : RelationType.Brother;
                    if (relation.RelationType == RelationType.Child)
                        model.Childs.Add(relation.To);
                    else
                        model.Brothers.Add(relation.To);
                }
            }
            #endregion

            #region 加载DataModel事件信息
            IEnumerable<XElement> eventColumns = xd.Root.Element("events") == null ? null : xd.Root.Element("events").Elements();
            model.DataModelEvents = new System.Collections.ObjectModel.Collection<DataModelEventInfo>();
            if (eventColumns != null)
            {
                foreach (XElement column in eventColumns)
                {
                    DataModelEventInfo info = new DataModelEventInfo();
                    info.EventName = column.Attribute("name") == null ? string.Empty : column.Attribute("name").Value;
                    info.EventExpr = column.Attribute("method") == null ? string.Empty : column.Attribute("method").Value;

                    if (!model.DataModelEvents.Contains(info))
                    {
                        model.DataModelEvents.Add(info);
                    }
                }
            }

            #endregion

            return model;
        }
    }
}
